/**
 * @file bio.c
 * @date 23.05.04
 * @author lyp
 * @brief 磁盘缓存管理模块，维护了一个buf结构体数组，实现了缓存的分配、读写、释放等功能
 * @version 0.1
 * @status Stable
*/

#include "types.h"
#include "param.h"
// #include "spinlock.h"
// #include "sleeplock.h"
#include "riscv.h"
#include "defs.h"
#include "fs.h"
#include "buf.h"

struct {
  // 锁目前可能用不到，有关锁的代码都将注释
  /*struct spinlock lock;*/
  struct buf buf[NBUF];

  // 双端链表head，用于存储所有的缓存块，链表按照缓存块最近使用的时间排序
  // head.next 指向最近使用的缓存块，head.prev 指向最久未使用的缓存块
  struct buf head;
} bcache;

/**
 * @brief 初始化缓冲区缓存，创建一个缓冲区的链表
 * @brief 最近使用的缓冲区在链表头部，最不常用的缓冲区在链表尾部，LRU
*/
void
binit(void)
{
  struct buf *b;

  /*initlock(&bcache.lock, "bcache");*/

  // 构建缓存的双端链表
  bcache.head.prev = &bcache.head;
  bcache.head.next = &bcache.head;
  for(b = bcache.buf; b < bcache.buf+NBUF; b++){
    b->next = bcache.head.next;
    b->prev = &bcache.head;
    /*initsleeplock(&b->lock, "buffer");*/
    bcache.head.next->prev = b;
    bcache.head.next = b;
  }
}

/**
 * @brief 查找特定设备上的块是否在缓冲区中
 * @param dev 设备号
 * @param blockno 块号
 * @return buf 缓冲区
*/
static struct buf*
bget(uint dev, uint blockno)
{
  struct buf *b;

  /*acquire(&bcache.lock);*/

  // 块已经被缓存，增加缓冲区的引用计数并返回缓冲区
  for(b = bcache.head.next; b != &bcache.head; b = b->next){
    if(b->dev == dev && b->blockno == blockno){
      b->refcnt++;
     /* release(&bcache.lock);
      acquiresleep(&b->lock);*/
      return b;
    }
  }

  // 块没有被缓存，分配一个新的缓冲区并返回
  for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
    if(b->refcnt == 0) {
      b->dev = dev;
      b->blockno = blockno;
      b->valid = 0;
      b->refcnt = 1;
     /* release(&bcache.lock);
      acquiresleep(&b->lock);*/
      return b;
    }
  }
  panic("bget: no buffers");
}

/**
 * @brief 返回一个缓冲区，其中包含指定块的内容
 * @param dev 设备号
 * @param blockno 块号
 * @return buf 缓冲区
*/
struct buf*
bread(uint dev, uint blockno)
{
  struct buf *b;

  b = bget(dev, blockno);
  if(!b->valid) {
    virtio_disk_rw(b, 0);
    b->valid = 1;
  }
  return b;
}

/**
 * @brief 将一个缓冲区的内容写入到磁盘中
 * @param buf 缓冲区
*/
void
bwrite(struct buf *b)
{
  /*if(!holdingsleep(&b->lock))
    panic("bwrite");*/
  virtio_disk_rw(b, 1);
}


/**
 * @brief 释放一个缓冲区，若当前的引用计数为0，则会被移动到链表头部以表示最近使用
 * @param buf 缓冲区
*/
void
brelse(struct buf *b)
{
  /*if(!holdingsleep(&b->lock))
    panic("brelse");

  releasesleep(&b->lock);

  acquire(&bcache.lock);*/
  b->refcnt--;
  if (b->refcnt == 0) {
    
    b->next->prev = b->prev;
    b->prev->next = b->next;
    b->next = bcache.head.next;
    b->prev = &bcache.head;
    bcache.head.next->prev = b;
    bcache.head.next = b;
  }
  
  /*release(&bcache.lock);*/
}

/**
 * @brief 增加引用计数值
 * @param buf 缓冲区
*/
void
bpin(struct buf *b) {
  // acquire(&bcache.lock);
  b->refcnt++;
  // release(&bcache.lock);
}

/**
 * @brief 减少引用计数值
 * @param buf 缓冲区
*/
void
bunpin(struct buf *b) {
  // acquire(&bcache.lock);
  b->refcnt--;
  // release(&bcache.lock);
}


